import { isEmptyNode } from './assert';
import { inlineTagNames, paraTagNames } from './config';

function clearEmptyNode(node) {
  if(!node || !(node instanceof Node)){
    console.error(`clear empty node: ${node} is not a node`);
    return;
  }

  if(isEmptyNode(node)) {
    if(node.parentNode) {
      node.parentNode.removeChild(node);
    }
  }
}

// merge same type node
function normalize(root) {
  if(!root || !(root instanceof Node)){
    console.error(`normalize: ${root} is not a node`);
    return;
  }
	const q = [root];
	while(q.length) {
		let cur = q.shift();
		let sib = q[0];
		if(!q.length || cur.parentNode !== sib.parentNode) {
			if(cur.nodeType === Node.ELEMENT_NODE) cur.childNodes.forEach(node => {
				q.push(node);
			});
			continue;
		} else {
			const parent = cur.parentNode;
			while (cur.nodeType === sib.nodeType && cur.parentNode === sib.parentNode) {
				if(cur.nodeType === Node.ELEMENT_NODE && cur.tagName === sib.tagName
          && inlineTagNames.some(tag => tag === cur.tagName)) {
          let sibChildNodes = sib.childNodes;
          while(sibChildNodes.length) {
            cur.appendChild(sibChildNodes[0]);
          }
					parent.removeChild(sib);
					q.shift();
				} else if (cur.nodeType === Node.TEXT_NODE) {
					cur.nodeValue += sib.nodeValue;
					parent.removeChild(sib);
					q.shift();
				} else {
					break;
				}
				if(!q.length) break;
				else sib = q[0];
			} 
			if (cur.nodeType === Node.ELEMENT_NODE) {
				cur.childNodes.forEach(node => {
					q.push(node);
				});
			}
		}
	}
}

// remove the same tag
function simplify(root) {
  if(!root || !(root instanceof Node)){
    console.error(`simplify: ${root} is not a node`);
    return;
  }
  const q = [root];
  while(q.length) {
    let node = q.shift();
    if(node.nodeType !== Node.ELEMENT_NODE) continue;
    const dict = {};
    let path = node;
    let repeatFlag = false;
    while(path != root) {
      if(dict[path.tagName] && !paraTagNames.includes(path.tagName)) {
        repeatFlag = true;
        break;
      } else {
        dict[path.tagName] = true;
        path = path.parentNode;
      }
    }
    if(repeatFlag) {
      let frag = new DocumentFragment();
      let nodes = node.childNodes;
      while(nodes.length) {
        q.push(nodes[0]);
        frag.appendChild(nodes[0]);
      }
      let parent = node.parentNode;
      parent.insertBefore(frag, node);
      parent.removeChild(node);
    } else {
    	node.childNodes.forEach(node => q.push(node));
    }
  }
}

function removeEmpty(root) {
  if(!root || !(root instanceof Node)){
    console.error(`remove empty: ${root} is not a node`);
    return;
  }
  let q = [];
  root.childNodes.forEach(node => q.push(node));
  while(q.length) {
    let node = q.shift();
    if(isEmptyNode(node)) clearEmptyNode(node);
    else {
      node.childNodes.forEach(node => q.push(node));
    }
  }
}

function removeEmptyTagList(node) {
  while(isEmptyNode(node) && !paraTagNames.includes(node.tagName)) node = node.parentNode;
  removeEmpty(node);
}

export {
  clearEmptyNode,
  normalize,
  simplify,
  removeEmpty
}